return edges;
}
-char gfxpoly_check(gfxpoly_t*poly)
+char gfxpoly_check(gfxpoly_t*poly, char updown)
{
current_polygon = poly;
- dict_t*d = dict_new2(&point_type);
+ dict_t*d1 = dict_new2(&point_type);
+ dict_t*d2 = dict_new2(&point_type);
int s,t;
gfxpolystroke_t*stroke = poly->strokes;
for(;stroke;stroke=stroke->next) {
that the endpoint multiplicity is two */
for(s=0;s<stroke->num_points;s++) {
point_t p = stroke->points[s];
- int num = (s>=1 && s<stroke->num_points-1)?2:1; // mid points are two points (start+end)
- if(!dict_contains(d, &p)) {
- dict_put(d, &p, (void*)(ptroff_t)num);
+ int num_xor = (s>=1 && s<stroke->num_points-1)?2:1; // mid points are two points (start+end)
+ int num_circ = (s>=1 && s<stroke->num_points-1)?0:(s==0?1:-1);
+ if(stroke->dir==DIR_UP)
+ num_circ=-num_circ;
+
+ if(!dict_contains(d1, &p)) {
+ dict_put(d1, &p, (void*)(ptroff_t)num_xor);
+ if(updown) {
+ assert(!dict_contains(d2, &p));
+ dict_put(d2, &p, (void*)(ptroff_t)num_circ);
+ }
} else {
- int count = (ptroff_t)dict_lookup(d, &p);
- dict_del(d, &p);
- count+=num;
- dict_put(d, &p, (void*)(ptroff_t)count);
+ int count = (ptroff_t)dict_lookup(d1, &p);
+ dict_del(d1, &p);
+ count+=num_xor;
+ dict_put(d1, &p, (void*)(ptroff_t)count);
+
+ if(updown) {
+ assert(dict_contains(d2, &p));
+ count = (ptroff_t)dict_lookup(d2, &p);
+ dict_del(d2, &p);
+ count+=num_circ;
+ dict_put(d2, &p, (void*)(ptroff_t)count);
+ }
}
}
}
- DICT_ITERATE_ITEMS(d, point_t*, p, void*, c) {
- int count = (ptroff_t)c;
+ DICT_ITERATE_ITEMS(d1, point_t*, p1, void*, c1) {
+ int count = (ptroff_t)c1;
if(count&1) {
- fprintf(stderr, "Point (%d,%d) occurs %d times\n", p->x, p->y, count);
- dict_destroy(d);
+ fprintf(stderr, "Point (%d,%d) occurs %d times\n", p1->x, p1->y, count);
+ dict_destroy(d1);
return 0;
}
}
- dict_destroy(d);
+ if(updown) {
+ DICT_ITERATE_ITEMS(d2, point_t*, p2, void*, c2) {
+ int count = (ptroff_t)c2;
+ if(count!=0) {
+ if(count>0) fprintf(stderr, "Point (%d,%d) has %d more incoming than outgoing segments\n", p2->x, p2->y, count);
+ if(count<0) fprintf(stderr, "Point (%d,%d) has %d more outgoing than incoming segments\n", p2->x, p2->y, -count);
+ dict_destroy(d2);
+ return 0;
+ }
+ }
+ }
+ dict_destroy(d1);
+ dict_destroy(d2);
return 1;
}
actlist_verify(actlist, y-1);
#endif
edgestyle_t*fill = 0;
- int dir_up = 0;
- int dir_down = 0;
+ int wind = 0;
do {
assert(e->s1->fs);
if(fill && x != e->p.x) {
-#ifdef DEBUG
- fprintf(stderr, "%d) draw horizontal line from %d to %d\n", y, x, e->p.x);
-#endif
+ assert(abs(wind)==1);
assert(x<e->p.x);
- assert(dir_up || dir_down);
gfxpolystroke_t*stroke = rfx_calloc(sizeof(gfxpolystroke_t));
stroke->next = poly->strokes;
stroke->num_points = 2;
stroke->points = malloc(sizeof(point_t)*2);
- if(dir_up < 0 || dir_down > 0) {
- stroke->dir = DIR_UP;
- } else {
+
+ if(wind>0) {
stroke->dir = DIR_DOWN;
+ } else {
+ stroke->dir = DIR_UP;
}
+#ifdef DEBUG
+ fprintf(stderr, "%d) draw horizontal line from %d to %d (dir=%s)\n", y, x, e->p.x, stroke->dir==DIR_UP?"up":"down");
+#endif
stroke->fs = fill;
point_t a,b;
a.y = b.y = y;
- /* we draw from low x to high x so that left/right fillstyles add up
- (because the horizontal line's fill style controls the area *below* the line)
- */
- a.x = e->p.x;
- b.x = x;
+ a.x = x;
+ b.x = e->p.x;
stroke->points[0] = a;
stroke->points[1] = b;
#ifdef CHECKS
/* the output should always be intersection free polygons, so check this horizontal
line isn't puncturing any segments in the active list */
- segment_t* start = actlist_find(actlist, b, b);
- segment_t* s = actlist_find(actlist, a, a);
+ segment_t* start = actlist_find(actlist, a, a);
+ segment_t* s = actlist_find(actlist, b, b);
while(s!=start) {
assert(s->a.y == y || s->b.y == y);
s = s->left;
e->s2 = 0;
hqueue_put(&hqueue, e);
left = actlist_left(actlist, s);
- dir_down += e->s1->dir==DIR_UP?1:-1;
+ wind += e->s1->dir==DIR_DOWN?-1:1;
break;
}
case EVENT_END: {
left = actlist_left(actlist, s);
actlist_delete(actlist, s);
advance_stroke(0, &hqueue, s->stroke, s->polygon_nr, s->stroke_pos);
- dir_up += e->s1->dir==DIR_UP?1:-1;
+ wind += e->s1->dir==DIR_DOWN?1:-1;
break;
}
default: assert(0);
#endif
#ifdef DEBUG
- fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d\n",
+ fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d dir:%s\n",
y, e->type==EVENT_START?"start":"end",
s->nr,
left?left->nr:-1,
- x);
+ x, s->dir==DIR_UP?"up":"down");
#endif
if(e->type == EVENT_END)
#ifdef CHECKS
edgestyle_t*bleeding = fill;
assert(!bleeding);
+ segment_t*s = actlist_leftmost(actlist);
+ int dir = 0;
+ while(s) {
+ dir += s->dir==DIR_UP?-1:1;
+ s = actlist_right(actlist, s);
+ }
+ assert(!dir);
#endif
}
void gfxpoly_fail(char*expr, char*file, int line, const char*function);
-char gfxpoly_check(gfxpoly_t*poly);
+char gfxpoly_check(gfxpoly_t*poly, char updown);
int gfxpoly_num_segments(gfxpoly_t*poly);
int gfxpoly_size(gfxpoly_t*poly);
void gfxpoly_dump(gfxpoly_t*poly);
l->num++;
}
#define CUT 0.5
-static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2, edgestyle_t*fs, int polygon_nr)
+static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2, edgestyle_t*fs, segment_dir_t dir, int polygon_nr)
{
x1 *= buf->zoom;
y1 *= buf->zoom;
y2 *= buf->zoom;
double diffx, diffy;
double ny1, ny2, stepx;
- segment_dir_t dir = DIR_DOWN;
+
if(y2 < y1) {
- dir = DIR_UP;
+ dir ^= DIR_UP^DIR_DOWN;
double x,y;
x = x1;x1 = x2;x2=x;
y = y1;y1 = y2;y2=y;
}
+
diffx = x2 - x1;
diffy = y2 - y1;
ny1 = floor(y1)+CUT;
double posx=0;
double startx = x1;
+ //printf("line %d from %f to %f dir=%s\n", polygon_nr, y1, y2, dir==DIR_UP?"up":"down");
+
while(posy<=endy) {
double xx = startx + posx;
add_pixel(buf, xx, posy, dir, fs, polygon_nr);
for(t=0;t<stroke->num_points-1;t++) {
point_t a = stroke->points[t];
point_t b = stroke->points[t+1];
- add_line(buf, a.x, a.y, b.x, b.y, stroke->fs, polygon_nr);
+ add_line(buf, a.x, a.y, b.x, b.y, stroke->fs, stroke->dir, polygon_nr);
}
}
fill_bitwise(line, lastx, width8*8);
assert(line[width8-1]&0x01);
bleeding = 1;
+ exit(1);
+
}
}
gfxdrawer_target_poly(&d, gridsize);
draw_stroke(line, &d, width, cap_style, joint_style, miterLimit);
gfxpoly_t*poly = (gfxpoly_t*)d.result(&d);
- assert(gfxpoly_check(poly));
+ assert(gfxpoly_check(poly, 1));
gfxpoly_t*poly2 = gfxpoly_process(poly, 0, &windrule_circular, &onepolygon);
gfxpoly_destroy(poly);
return poly2;
gfxline_t*box3 = gfxline_makerectangle(-100,-100,100,100);
//gfxline_append(box2, box3);
- gfxpoly_check(gfxpoly_from_stroke(box1, 2.0, gfx_capRound, gfx_joinRound, 0, 0.05));
+ gfxpoly_check(gfxpoly_from_stroke(box1, 2.0, gfx_capRound, gfx_joinRound, 0, 0.05), 1);
gfxmatrix_t matrix;
memset(&matrix, 0, sizeof(gfxmatrix_t));
double zoom = 1.0;
- if(!gfxpoly_check(poly1)) {
+ if(!gfxpoly_check(poly1, 0)) {
printf("bad polygon\n");
continue;
}
gfxpoly_t*poly2 = gfxpoly_process(poly1, 0, rule, &onepolygon);
+ assert(gfxpoly_check(poly2, 1));
int pass;
for(pass=0;pass<2;pass++) {
intbbox_t bbox = intbbox_from_polygon(poly1, zoom);
unsigned char*bitmap1 = render_polygon(poly1, &bbox, zoom, rule, &onepolygon);
- unsigned char*bitmap2 = render_polygon(poly2, &bbox, zoom, &windrule_evenodd, &onepolygon);
+ unsigned char*bitmap2 = render_polygon(poly2, &bbox, zoom, &windrule_circular, &onepolygon);
if(!bitmap_ok(&bbox, bitmap1) || !bitmap_ok(&bbox, bitmap2)) {
save_two_bitmaps(&bbox, bitmap1, bitmap2, "error.png");
assert(!"error in bitmaps");
}
free(bitmap1);
free(bitmap2);
-
+
// second pass renders the 90° rotated version
rotate90(poly1);
rotate90(poly2);
fprintf(stderr, "%d segments (max so far: %d/%d)\n", size, max_segments, max_any_segments);
}
- if(!gfxpoly_check(poly1)) {
+ if(!gfxpoly_check(poly1, 0)) {
gfxpoly_destroy(poly1);
fprintf(stderr, "bad polygon\n");
return;
//gfxpoly_t*p = gfxpoly_fromstroke(l, width, gfx_capRound, gfx_joinRound, 500);
gfxpoly_t*p1 = gfxpoly_from_stroke(l, width, gfx_capRound, gfx_joinRound, 500, 0.05);
- assert(gfxpoly_check(p1));
+ assert(gfxpoly_check(p1, 1));
//gfxpoly_t*p2 = gfxpoly_from_fill(f, 0.05);
gfxline_t*l2 = gfxline_clone(l);
s, -c, -(350+x1)*s+(350+y1)*c+350};
gfxline_transform(l2, &m);
gfxpoly_t*p2 = gfxpoly_from_stroke(l2, width, gfx_capRound, gfx_joinRound, 500, 0.05);
- assert(gfxpoly_check(p2));
+ assert(gfxpoly_check(p2, 1));
gfxpoly_t*p3 = gfxpoly_intersect(p1, p2);
- assert(gfxpoly_check(p3));
+ assert(gfxpoly_check(p3, 1));
//gfxpoly_t*p4 = gfxpoly_from_fill(f, 0.05);
//gfxpoly_t*p5 = gfxpoly_intersect(p1, p4);
edgestyle_t* circular_diff(windstate_t*left, windstate_t*right)
{
- if(left->is_filled==right->is_filled) {
+ if(left->is_filled==right->is_filled)
return 0;
- } else if(left->is_filled) {
- return &edgestyle_down;
- } else {//right->is_filled
- return &edgestyle_up;
- }
+ else
+ return &edgestyle_default;
}
windrule_t windrule_circular = {